//
// Created by chizuru on 2025/9/2.
//

#pragma once
#include "OperationResult.h"
#include <algorithm>
#include <thread>
#include <optional>

struct RetryPolicy {
    int maxAttempts = 2; // initial + retries
    std::chrono::milliseconds delay{50};

    // helper trait: is std::optional
    template <typename T> static constexpr bool is_optional_v = false;
    template <typename T> static constexpr bool is_optional_v<std::optional<T>> = true;

    // helper trait: has .empty()
    template <typename, typename = void>
    struct has_empty : std::false_type {};

    template <typename T>
    struct has_empty<T, std::void_t<decltype(std::declval<T>().empty())>> : std::true_type {};

    template <typename T>
    static constexpr bool has_empty_v = has_empty<T>::value;

    template <typename Func>
    auto withRetry(Func&& f) const {
        using Ret = std::invoke_result_t<Func>; // callable with no args

        for (int attempt = 1; attempt <= maxAttempts; ++attempt) {
            Ret r = std::invoke(std::forward<Func>(f));

            if constexpr (std::is_same_v<Ret, OperationResult>) {
                if (r.success) return r;
            }
            else if constexpr (is_optional_v<Ret>) {
                if (r.has_value()) return r;
            }
            else if constexpr (std::is_convertible_v<Ret, bool>) {
                // raw pointers, smart pointers with operator bool, or types explicitly convertible
                if (r) return r;
            }
            else if constexpr (has_empty_v<Ret>) {
                // containers like std::vector, std::string, ...
                if (!r.empty()) return r;
            }
            else {
                // 无法判断“成功”或“空”的类型 —— 只能继续重试并最终返回默认构造值
            }

            if (attempt < maxAttempts)
                std::this_thread::sleep_for(delay);
        }

        // return appropriate empty/failure for Ret
        if constexpr (std::is_same_v<Ret, OperationResult>) {
            return OperationResult::Fail(ErrorCode::Unknown, "all retries failed");
        } else if constexpr (is_optional_v<Ret>) {
            return Ret{};
        } else if constexpr (std::is_same_v<Ret, bool>) {
            return false;
        } else {
            return Ret{};
        }
    }
};

